#include "copyright.h"
#include "system.h"
#include "syscall.h"
#include "process.h"
#include "../network/post.h"

#include <iostream>
#include <list>

#define MAX_SERVER_LOCKS	1000
#define MAX_SERVER_CVS      1000
#define MAX_SERVER_MVS      1000
using namespace std;

typedef struct ServerLockEntry{
	ServerLock *lock;
	int machineID;
	int mailboxID;
	int acquireCount;
	bool isDeleted;
	bool isToBeDeleted;
}ServerLockEntry;

typedef struct ServerCVEntry{
	ServerCondition *cv;
	int waitCount;
	bool isDeleted;
	bool isToBeDeleted;
}ServerCVEntry;

typedef struct ServerMVEntry{
	int *monitor;
	char* monitorName;
	bool inUse; //0 is not in use. 1 is in use.
	int arraySize;
}ServerMVEntry;

ServerLockEntry ServerLockTable[MAX_SERVER_LOCKS];
ServerCVEntry ServerCVTable[MAX_SERVER_CVS];
ServerMVEntry ServerMVTable[MAX_SERVER_MVS];

int clientCount;
bool doReply; // 0 = dont do reply, 1 = do reply.

//=================================================//
//----------------LOCK SYSCALLS--------------------//
//=================================================//
/*
 *	findServerLock helper method to find a free lock in the lock table.
 *	1. Searches for  the first lock that returns NULL
 *	2. return the index of that lock.
 *	3. If no locks are found, return -1. 
*/
int findServerLock()
{
	int result = -1;
	for (int i = 0; i < MAX_SERVER_LOCKS; i++)
	{
		if (ServerLockTable[i].lock == NULL)
		{
			result = i;
			break;
		}
	}
	return result;
}
/*
 *	CreateServerLock_Syscall:
 *	1. Searches through the lock table to find a lock with the same name
 *		-If found, return that lock's ID.
 *		-If not found go to step 2.
 *	2. Call findServerLock to find a free lock and store result in freeLock
 *		-If the method returns anything other than -1, use this index to create the lock.
 *		-If -1, no more locks free. 
*/
int CreateServerLock_Syscall(int machID, int mailID, char* name)
{
	printf("In CreateServerLockSyscall - with name [%s].\n", name);
	for (int i = 0; i < MAX_SERVER_LOCKS; i++)
	{
		if (ServerLockTable[i].lock != NULL)
		{
			if (strcmp(name, ServerLockTable[i].lock->name) == 0)
			{
				printf("Lock with the same name [%s], with index [%d] already exist.\n", name, i);
				return i;
			}
		}
	}
	int freeLock = findServerLock();
	if( freeLock != -1 )
	{
		printf("Creating lock [%d] now.\n", freeLock);
		ServerLockTable[freeLock].lock = new ServerLock(name);
		ServerLockTable[freeLock].machineID = machID;
		ServerLockTable[freeLock].mailboxID = mailID;	
	}
	else
	{
		printf("No more locks free on the server in CreateServerLockSyscall.\n");
	}
	return freeLock;
}

/*
 *	DeleteServerLock_Syscall:
 *	1. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. If the lock is not busy and no one is trying to acquire it delete it.
 *  3. Else, set isToBeDeleted to true so it can be deleted later.
*/
void DeleteServerLock_Syscall(int lockid)
{
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In DeleteServerLockSyscall - the lock [%d] id passed in is null.\n", lockid);
		return;
	}
	
	if (!ServerLockTable[lockid].lock->isBusy() && ServerLockTable[lockid].acquireCount == 0)
	{
		printf("In DeleteServerLockSyscall - Now deleting lock [%d].\n", lockid);
		delete ServerLockTable[lockid].lock;
		ServerLockTable[lockid].lock = NULL;
		ServerLockTable[lockid].machineID = -1;
		ServerLockTable[lockid].mailboxID = -1;
		ServerLockTable[lockid].acquireCount = 0;	
		ServerLockTable[lockid].isToBeDeleted = false;	
		return;
	}
	else
	{
		printf("In DeleteServerLockSyscall - the lock [%d] is still in use, mark it to be deleted.\n", lockid);
		ServerLockTable[lockid].isToBeDeleted = true;
		return;
	}
}

/*
 *	AcquireServerLock_Syscall:
 *	1. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. If the lock is busy, wait, doReply = false.
 *  3. Else, acquire the lock.
*/
void AcquireServerLock_Syscall(int machID, int mailID, int lockid)
{
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In AcquireServerLockSyscall - the lock [%d] id passed in is null.\n", lockid);
		return;
	}
	
	if (ServerLockTable[lockid].lock->isBusy())
	{
		printf("In AcquireServerLockSyscall - lock [%d] is busy, now adding machine [%d] to the lock wait queue.\n", lockid, machID);
		doReply = false;
		ServerLockTable[lockid].acquireCount++;
		ServerLockTable[lockid].lock->Acquire(machID, mailID);
		return;
	}
	else
	{
		printf("In AcquireServerLockSyscall - acquiring lock [%d] now.\n", lockid);
		ServerLockTable[lockid].acquireCount++;
		ServerLockTable[lockid].lock->Acquire(machID, mailID);
		return;
	}	
}

/*
 *	ReleaseServerLock_Syscall:
 *	1. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. Release the lock
 *  3. Check if the lock's been marked to be deleted. If so, delete the lock if it's not busy.
*/
void ReleaseServerLock_Syscall(int machID, int mailID, int lockid)
{
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In ReleaseServerLockSyscall - the lock [%d] id passed in is null.\n", lockid);
		return;
	}
	
	printf("In ReleaseServerLockSyscall - machine [%d] Releasing lock [%d] now.\n",machID, lockid);
	ServerLockTable[lockid].acquireCount--;
	ServerLockTable[lockid].lock->Release(machID, mailID);
	
	if (ServerLockTable[lockid].isToBeDeleted && !ServerLockTable[lockid].lock->isBusy() && ServerLockTable[lockid].acquireCount == 0)
	{
		printf("In ReleaseServerLockSyscall - deleting lock [%d].\n", lockid);
		delete ServerLockTable[lockid].lock;
		ServerLockTable[lockid].lock = NULL;
		ServerLockTable[lockid].machineID = -1;
		ServerLockTable[lockid].mailboxID = -1;
		ServerLockTable[lockid].acquireCount = 0;	
		ServerLockTable[lockid].isToBeDeleted = false;	
	}
	return;
}
//=================================================//
//-------------(END) LOCK SYSCALLS-----------------//
//=================================================//
//=================================================//
//------------------CV SYSCALLS--------------------//
//=================================================//
/*
 *	findServerCV helper method to find a free cv in the cv table.
 *	1. Searches for  the first cv that returns NULL
 *	2. return the index of that cv.
 *	3. If no cvs are found, return -1. 
*/
int findServerCV()
{
	int result = -1;
	for (int i = 0; i < MAX_SERVER_CVS; i++)
	{
		if (ServerCVTable[i].cv == NULL)
		{
			result = i;
			break;
		}
	}
	return result;
}

/*
 *	CreateServerCondition_Syscall:
 *	1. Searches through the cv table to find a cv with the same name
 *		-If found, return that cv's ID.
 *		-If not found go to step 2.
 *	2. Call findServerCV to find a free cv and store result in freeCV
 *		-If the method returns anything other than -1, use this index to create the cv.
 *		-If -1, no more cvs free. 
*/
int CreateServerCondition_Syscall(char* name)
{
	printf("In CreateServerCondition_Syscall - with name [%s].\n", name);
	for (int i = 0; i < MAX_SERVER_CVS; i++)
	{
		if (ServerCVTable[i].cv != NULL)
		{
			if (strcmp(name, ServerCVTable[i].cv->name) == 0)
			{
				printf("CV with the same name [%s], with index [%d] already exist.\n", name, i);
				return i;
			}
		}
	}
	int freeCV = findServerCV();
	if( freeCV != -1 )
	{
		printf("Creating CV [%d] now.\n", freeCV);
		ServerCVTable[freeCV].cv = new ServerCondition(name);
		ServerCVTable[freeCV].waitCount = 0;
		ServerCVTable[freeCV].isDeleted = false;
		ServerCVTable[freeCV].isToBeDeleted = false;		
	}
	else
	{
		printf("No more cvs free on the server in CreateServerCondition_Syscall.\n");
	}
	return freeCV;
}

/*
 *	DeleteServerCondition_Syscall:
 *	1. Check if the cv associated with the cvid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. If the cv is not busy and no one is trying to wait on it delete it.
 *  3. Else, set isToBeDeleted to true so it can be deleted later.
*/
void DeleteServerCondition_Syscall(int cvid)
{
	if (ServerCVTable[cvid].cv == NULL)
	{
		printf("In DeleteServerCondition_Syscall - the cv [%d] id passed in is null.\n", cvid);
		return;
	}
	
	if (ServerCVTable[cvid].cv->isEmpty() && ServerCVTable[cvid].waitCount == 0)
	{
		printf("In DeleteServerCondition_Syscall - Now deleting cv [%d].\n", cvid);
		delete ServerCVTable[cvid].cv;
		ServerCVTable[cvid].cv = NULL;
		ServerCVTable[cvid].waitCount = 0;	
		ServerCVTable[cvid].isToBeDeleted = false;	
		return;
	}
	else
	{
		printf("In DeleteServerCondition_Syscall - the cv [%d] is still in use, mark it to be deleted.\n", cvid);
		ServerLockTable[cvid].isToBeDeleted = true;
		return;
	}
}

/*
 *	WaitServerCondition_Syscall:
 *	1. Check if the cv associated with the cvid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 3.
 *  3. Wait on the CV. doReply = false.
*/
void WaitServerCondition_Syscall(int lockid, int cvid)
{
	if (ServerCVTable[cvid].cv == NULL)
	{
		printf("In WaitServerCondition_Syscall - the cv [%d] id passed in is null.\n", cvid);
		return;
	}
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In WaitServerCondition_Syscall - the lock [%d] id passed in is null.\n", lockid);
		return;
	}
	
	printf("In WaitServerCondition_Syscall - now waiting on cv [%d] with lock [%d].\n", cvid, lockid);
	doReply = false;
	ServerCVTable[cvid].waitCount++;
	ServerCVTable[cvid].cv->Wait(ServerLockTable[lockid].lock);
}

/*
 *	SignalServerCondition_Syscall:
 *	1. Check if the cv associated with the cvid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 3.
 *  3. Signal on the CV.
 *  4. If the CV has been marked to be deleted, if so, delete it.
*/
int SignalServerCondition_Syscall(int lockid, int cvid)
{
	if (ServerCVTable[cvid].cv == NULL)
	{
		printf("In SignalServerCondition_Syscall - the cv [%d] id passed in is null.\n", cvid);
		return -1;
	}
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In SignalServerCondition_Syscall - the lock [%d] id passed in is null.\n", lockid);
		return -1;
	}
	printf("In SignalServerCondition_Syscall - signaling cv [%d] with lock [%d] now.\n", cvid, lockid);
	ServerCVTable[cvid].cv->Signal(ServerLockTable[lockid].lock);
	ServerCVTable[cvid].waitCount--;
		
	if (ServerCVTable[cvid].isToBeDeleted && ServerCVTable[cvid].cv->isEmpty() && ServerCVTable[cvid].waitCount == 0)
	{
		printf("In SignalServerCondition_Syscall - Now deleting cv [%d].\n", cvid);
		delete ServerCVTable[cvid].cv;
		ServerCVTable[cvid].cv = NULL;
		ServerCVTable[cvid].waitCount = 0;	
		ServerCVTable[cvid].isToBeDeleted = false;			
	}
	return 1;
}

/*
 *	BroadcastServerCondition_Syscall:
 *	1. Check if the cv associated with the cvid is NULL.
 *		-If so, return.
 *		-If not, go to step 2.
 *	2. Check if the lock associated with the lockid is NULL.
 *		-If so, return.
 *		-If not, go to step 3.
 *  3. Broadcast on the CV.
*/
int BroadcastServerCondition_Syscall(int lockid, int cvid)
{
	if (ServerCVTable[cvid].cv == NULL)
	{
		printf("In BroadcastServerCondition_Syscall - the cv [%d] id passed in is null.\n", cvid);
		return -1;
	}
	if (ServerLockTable[lockid].lock == NULL)
	{
		printf("In BroadcastServerCondition_Syscall - the lock [%d] id passed in is null.\n", lockid);
		return -1;
	}
	
	printf("In BroadcastServerCondition_Syscall - Broadcasting on cv [%d], lock [%d] now.\n", cvid, lockid);
	ServerCVTable[cvid].cv->Broadcast(ServerLockTable[lockid].lock);
	return 1;
}
//=================================================//
//---------------(END) CV SYSCALLS-----------------//
//=================================================//
//=================================================//
//----------------MONITOR SYSCALLS-----------------//
//=================================================//
/*
 *	findServerMV helper method to find a free mv in the mv table.
 *	1. Searches for  the first mv that returns NULL
 *	2. return the index of that mv.
 *	3. If no mvs are found, return -1. 
*/
int findMV()
{
	int result = -1;
	for (int i = 0; i < MAX_SERVER_MVS; i++)
	{
		if (ServerMVTable[i].inUse == 0)
		{
			//if the mv is null, make this our new cv.
			//pass the index of this mv. 
			result = i;
			break;
		}
	}
	return result;
}

/*
 *	CreateServerMonitor_Syscall:
 *	1. Searches through the mv table to find a mv with the same name
 *		-If found, return that mv's ID.
 *		-If not found go to step 2.
 *	2. Call findMV to find a free mv and store result in freeMV
 *		-If the method returns anything other than -1, use this index to create the mv.
 *		-If -1, no more mvs free. 
*/
int CreateServerMonitor_Syscall(char* name, int arraysize)
{
	printf("In CreateServerMonitor_Syscall - with name [%s].\n", name);
	for (int i = 0; i < MAX_SERVER_MVS; i++)
	{
		if (ServerMVTable[i].inUse)
		{
			if (strcmp(name, ServerMVTable[i].monitorName) == 0)
			{
				printf("MV with the same name [%s], with index [%d] already exist.\n", name, i);
				return i;
			}
		}
	}
	int freeMV = findMV();
	if( freeMV != -1 )
	{
		ServerMVTable[freeMV].monitor = new int [arraysize];
		for(int i = 0; i < arraysize; i++)
		{
			ServerMVTable[freeMV].monitor[i] = -1;
		}
		ServerMVTable[freeMV].monitorName = name;
		ServerMVTable[freeMV].inUse = 1;
		ServerMVTable[freeMV].arraySize = arraysize;
	}
	else
	{
		printf("No more monitors free on the server in CreateServerMonitor_Syscall.\n");
	}
	return freeMV;
}

/*
 *	DeleteServerMonitor_Syscall:
 *	1. Delete the MV.
*/
void DeleteServerMonitor_Syscall(int monitorid)
{
	printf("In DeleteServerMonitor_Syscall - Deleting monitor [%d].\n", monitorid);
	delete[] ServerMVTable[monitorid].monitor;
	ServerMVTable[monitorid].monitorName=NULL;
	ServerMVTable[monitorid].inUse = 0;
	ServerMVTable[monitorid].arraySize = 0;
}

/*
 *	SetServerMonitor_Syscall:
 *	1. Check that the index passed in is valid. 
 *  2. If so, set the monitor.
*/
int SetServerMonitor_Syscall(int monitorid, int index, int arg)
{
	if( index > ServerMVTable[monitorid].arraySize-1 || index < 0)
	{
		printf("In SetServerMonitor_Syscall - Invalid index [%d] with val [%d] on monitor [%d].\n", index,arg, monitorid);
		return -1;
	}
	ServerMVTable[monitorid].monitor[index]=arg;
}

/*
 *	GetServerMonitor_Syscall:
 *	1. Check that the index passed in is valid. 
 *  2. If so, return the value at that index position.
*/
int GetServerMonitor_Syscall(int monitorid, int index)
{
	if( index > ServerMVTable[monitorid].arraySize-1 || index < 0)
	{
		printf("In GetMonitorServer_Syscall - Invalid index [%d] on monitor [%d].\n", index, monitorid);
		return -1;
	}
	return ServerMVTable[monitorid].monitor[index];
}

//=================================================//
//-------------(END) MONITOR SYSCALLS--------------//
//=================================================//
/*
 * This is the MessageParser that parses incoming messages and chooses the appropriate action.
 * The message parser works much like the execeptions handler in execeptions.cc
 * 1. Initialize data
 * 		-Initialize PacketHeader and MailHeader to send and receive mail.
 *		-Initialize the return value to -12345 so we can capture cases that return msgs with a generic rv
 * 		-Initialize data needed to store the messages (lock/cv/mv names, ids, etc..)
 * 2. Messages to the server comes in the form "%d^%d^%d", or however many arguments needed.
 *		-The first parameter is always the type of syscall. 
 *		-Each call to strtok will use "^" as the delimiter.
 *		-The first call to strtok() with the incoming message will return the syscall type.
 *		-Store the type in caseNum and create a switch block.
 * 3. Parse the rest of the message. Call the appropriate syscall based on the case
 *		-Each subsequent call to strtok with NULL instead of the str will yield the next argument for the message.
 *		-Since we know what message each syscall in execeptions.cc is writing, for ever case,
 *			parse the message and call the appropriate server syscall.
 * 4. Decide whether or not to send a reply.
 *		-doReply is always initialized to true. Acquire and Wait syscalls will set this to false.
 *		-If a syscall does not return a value, rv will be -12345, in which case, reply with the message 1.
 *		-If rv is anything else but -12345, reply with rv as the message.
*/
void MessageParser(PacketHeader &phdr, char* msg)
{
	char outgoingMsg[MaxMailSize];
	char* myMsg;
	myMsg = msg;
	PacketHeader pktHdrOut;
	MailHeader mailHdrOut;
	pktHdrOut.to = 1;
	pktHdrOut.from = 0;
	pktHdrOut.length = MaxMailSize;
	mailHdrOut.to = 1;
	mailHdrOut.from = 0;
	mailHdrOut.length = MaxMailSize;
	int rv = -12345;
	doReply = true;
	
	char* lockname;
	char* cvname;
	char* monitorname;
	int lockid, cvid, monitorid, size, val, index;
	int caseNum = atoi(strtok(myMsg,"^"));
	switch(caseNum)
	{
		case SC_CreateLock:
			DEBUG('n', "CreateServerLock syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockname = strtok(NULL, "^");
			//===THREE ARGS===[(1) MACHINE ID]===[(2) MAILBOX ID]===[(3) LOCK NAME]===//
			printf("lockname [%s], mailHdrOut.to [%d].\n", lockname, mailHdrOut.to);
			rv = CreateServerLock_Syscall(phdr.from, mailHdrOut.to, lockname);
		break;
		case SC_DeleteLock:
			DEBUG('n', "DeleteServerLock syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));
			printf("lockid [%d], mailHdrOut.to [%d], phdr.from [%d].\n", lockid, mailHdrOut.to, phdr.from);
			//===ONE ARGS===[(1) LOCK ID]===//
			DeleteServerLock_Syscall(lockid);
		break;
		case SC_AcquireLock:
			DEBUG('n', "AcquireServerLock syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));	
			//===THREE ARGS===[(1) MACHINE ID]===[(2) MAILBOX ID]===[(3) LOCK ID]===//
			printf("lockid [%d], mailHdrOut.to [%d], phdr.from [%d].\n", lockid, mailHdrOut.to, phdr.from);
			AcquireServerLock_Syscall(phdr.from, mailHdrOut.to, lockid);
		break;
		case SC_ReleaseLock:
			DEBUG('n', "ReleaseServerLock syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));
			printf("lockid [%d], mailHdrOut.to [%d], phdr.from [%d].\n", lockid, mailHdrOut.to, phdr.from);
			//===THREE ARGS===[(1) MACHINE ID]===[(2) MAILBOX ID]===[(3) LOCK ID]===//
			ReleaseServerLock_Syscall(phdr.from, mailHdrOut.to, lockid);
		break;
		case SC_CreateCondition:
			DEBUG('n', "CreateServerCondition syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			cvname = strtok(NULL, "^");
			//===ONE ARGS===[(1) CV NAME]===//
			rv = CreateServerCondition_Syscall(cvname);
		break;
		case SC_DeleteCondition:
			DEBUG('n', "DeleteServerCondition syscall.\n");
			//===ONE ARGS===[(1) CV ID]===//
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			cvid = atoi(strtok(NULL, "^"));
			DeleteServerCondition_Syscall(cvid);
		break;
		case SC_WaitCondition:
			DEBUG('n', "WaitServerCondition syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));			
			cvid = atoi(strtok(NULL, "^"));
			//===TWO ARGS===[(1) LOCK ID]===[(2) CV ID]===//
			WaitServerCondition_Syscall(lockid, cvid);
		break;
		case SC_SignalCondition:
			DEBUG('n', "SignalServerCondition syscall.\n");		
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));
			cvid = atoi(strtok(NULL, "^"));
			//===TWO ARGS===[(1) LOCK ID]===[(2) CV ID]===//
			rv = SignalServerCondition_Syscall(lockid, cvid);
		break;
		case SC_BroadcastCondition:
			DEBUG('n', "BroadcastServerCondition syscall.\n");		
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			lockid = atoi(strtok(NULL, "^"));
			cvid = atoi(strtok(NULL, "^"));
			//===TWO ARGS===[(1) LOCK ID]===[(2) CV ID]===//
			rv = BroadcastServerCondition_Syscall(lockid, cvid);
		break;	
		case SC_CreateMonitor:
			DEBUG('n', "CreateMonitor Syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			monitorname = strtok(NULL, "^");
			size = atoi(strtok(NULL, "^"));
			//===TWO ARGS===[(1) MONITOR NAME]===[(2) ARRAY SIZE]===//
			rv = CreateServerMonitor_Syscall(monitorname, size);
		break;
		case SC_DeleteMonitor:
			DEBUG('n', "DeleteMonitor Syscall. \n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			monitorid = atoi(strtok(NULL, "^"));			
			//===ONE ARGS===[(1) MONITOR ID]===//
			DeleteServerMonitor_Syscall(monitorid);
		break;
		case SC_GetMonitor:
			DEBUG('n', "GetMonitor Syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			monitorid = atoi(strtok(NULL, "^"));
			index = atoi(strtok(NULL, "^"));		
			//===TWO ARGS===[(1) MONITOR ID]===[(2) INDEX IN ARRAY]===//
			rv = GetServerMonitor_Syscall(monitorid, index);
		break;
		case SC_SetMonitor:
			DEBUG('n', "SetMonitor Syscall.\n");
			mailHdrOut.to = atoi(strtok(NULL, "^"));
			monitorid = atoi(strtok(NULL, "^"));
			index = atoi(strtok(NULL, "^"));		
			val = atoi(strtok(NULL, "^"));
			printf("val [%d], index [%d], monitorid [%d], mailHdrOut.to [%d].\n", val, index, monitorid, mailHdrOut.to);
			//===THREE ARGS===[(1) MONITOR ID]===[(2) INDEX IN ARRAY]===[(3) VALUE]===//
			rv = SetServerMonitor_Syscall(monitorid, index, val);
		break;	
		case SC_Exit:
			printf("In Exit Syscall.\n");
			DEBUG('n', "Exit Syscall. \n");
			clientCount--;
			mailHdrOut.to = atoi(strtok(NULL, "^"));
		break;
		case SC_StartClient:
			DEBUG('n', "StartClient Syscall. \n");
			clientCount++;
			mailHdrOut.to = atoi(strtok(NULL, "^"));
		break;
		default:
			DEBUG('n', "Unhandled Exception. of type %d\n", caseNum);
		break;
	}
	
	if (doReply)
	{
		printf("RETURN VALUE IS: [%d].\n", rv);
		if(rv != -12345)
		{
			sprintf(outgoingMsg, "%d", rv);
				
		}
		else
		{		
			sprintf(outgoingMsg, "%d", 1);
		}
		//reply to sender
		pktHdrOut.to = phdr.from;
		//server 0.
		mailHdrOut.from = 0;
		printf("Server Sending message now to machine [%d]\n", phdr.from);
		int postrv = postOffice->Send(pktHdrOut, mailHdrOut, outgoingMsg);
		if (!postrv)																
		{																			
			printf("PostOffice failed to send msg.\n");					
			interrupt->Halt();														
		}
	}
}

/*
 * This is the method called to start the server.
 * 1. Initialize data
 * 		-Sets the counter of clients to 5. (MAX_CLIENTS)
 *		-Initialize ServerLockTable, ServerCVTable, ServerMVTable
 *		-Initialize PacketHeader and MailHeader to send and receive msgs. 
 * 2. While(true) 
 *		- Wait for incoming messages.
 *  	- When a there is a incoming msg, Call MessageParser to parse the messge.
 *		- When clientCount reaches 0, terminate the server.
*/
void RunServer(){
	printf("Server is now initializing...\n");
	clientCount = 0;
	
	for(int i = 0 ; i < MAX_SERVER_LOCKS; i++)
	{
		ServerLockTable[i].lock = NULL;
		ServerLockTable[i].machineID = -1;
		ServerLockTable[i].mailboxID = -1;
		ServerLockTable[i].acquireCount = 0;
		ServerLockTable[i].isDeleted = true;
		ServerLockTable[i].isToBeDeleted = false;
	}
	
	for(int i = 0 ; i < MAX_SERVER_CVS; i++)
	{
		ServerCVTable[i].cv = NULL;
		ServerCVTable[i].waitCount = 0;
		ServerCVTable[i].isDeleted = true;
		ServerCVTable[i].isToBeDeleted = false;
	}
	
	for(int i = 0 ; i < MAX_SERVER_MVS; i++)
	{
		ServerMVTable[i].monitorName = NULL;
		ServerMVTable[i].inUse = 0; //0 = free.
		ServerMVTable[i].arraySize = 0;
	}	
	
	PacketHeader PktHdrIn, PktHdrOut;
	MailHeader mailHdrIn, mailHrdOut;
	char incomingMsg[MaxMailSize];
	PktHdrIn.to =0;
	PktHdrIn.from=1;
	PktHdrIn.length=MaxMailSize;
	PktHdrOut.to =1;
	PktHdrOut.from=0;
	PktHdrOut.length=MaxMailSize;
	mailHdrIn.to=0;
	mailHdrIn.from=1;
	mailHdrIn.length=MaxMailSize;
	mailHrdOut.to=1;
	mailHrdOut.from=0;
	mailHrdOut.length=MaxMailSize;
	
	printf("Done initializing.\n");
	
	while(true)
	{
		printf("Server is now waiting for incoming msgs.\n");
		postOffice->Receive(0,&PktHdrIn, &mailHdrIn, incomingMsg);
		MessageParser(PktHdrIn, incomingMsg);
		if (clientCount == 0)
		{
			//kill the server if no more clients
			printf("No more clients. Terminating the server now.\n");
			interrupt->Halt();
		}
	}
	interrupt->Halt();
}




